﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MPlusTree
{
    public class MPEntry<Key>
        where Key:MPKey, new()
    {
        private MPKey key;
        private float radius;
        private float disToParent;
        private float lMax;
        private float rMin;
        private ulong leftNode;
        private ulong rightNode;
        private MPNode<Key> node;
        private int position;

        public MPEntry()
        {
            key = null;
            radius = 0;
            disToParent = 0;
            lMax = float.MinValue;
            rMin = float.MaxValue;
            leftNode = 0;
            rightNode = 0;
            node = null;
            position = -1;
        }

        public int Size()
        {
            return key.Size() + sizeof(float) * 4 + sizeof(ulong) * 2 + sizeof(int);
        }

        public static int SizeFromKeySize(int keySize)
        {
            return keySize + sizeof(float) * 4 + sizeof(ulong) * 2 + sizeof(int);
        }

        public byte[] ToByte()
        {
            byte[] b = new byte[Size()];
            byte[] tmp;
            int index = 0;

            tmp = key.ToBytes();
            Array.Copy(tmp, 0, b, index, tmp.Length);
            index += tmp.Length;

            tmp = BitConverter.GetBytes(radius);
            Array.Copy(tmp, 0, b, index, tmp.Length);
            index += tmp.Length;

            tmp = BitConverter.GetBytes(disToParent);
            Array.Copy(tmp, 0, b, index, tmp.Length);
            index += tmp.Length;

            tmp = BitConverter.GetBytes(lMax);
            Array.Copy(tmp, 0, b, index, tmp.Length);
            index += tmp.Length;

            tmp = BitConverter.GetBytes(rMin);
            Array.Copy(tmp, 0, b, index, tmp.Length);
            index += tmp.Length;

            tmp = BitConverter.GetBytes(leftNode);
            Array.Copy(tmp, 0, b, index, tmp.Length);
            index += tmp.Length;

            tmp = BitConverter.GetBytes(rightNode);
            Array.Copy(tmp, 0, b, index, tmp.Length);
            index += tmp.Length;

            tmp = BitConverter.GetBytes(position);
            Array.Copy(tmp, 0, b, index, tmp.Length);
            index += tmp.Length;

            return b;
        }

        public void ToByte(byte[] b, int startIndex)
        {
            byte[] tmp;
            int index = startIndex;

            tmp = key.ToBytes();
            Array.Copy(tmp, 0, b, index, tmp.Length);
            index += tmp.Length;

            tmp = BitConverter.GetBytes(radius);
            Array.Copy(tmp, 0, b, index, tmp.Length);
            index += tmp.Length;

            tmp = BitConverter.GetBytes(disToParent);
            Array.Copy(tmp, 0, b, index, tmp.Length);
            index += tmp.Length;

            tmp = BitConverter.GetBytes(lMax);
            Array.Copy(tmp, 0, b, index, tmp.Length);
            index += tmp.Length;

            tmp = BitConverter.GetBytes(rMin);
            Array.Copy(tmp, 0, b, index, tmp.Length);
            index += tmp.Length;

            tmp = BitConverter.GetBytes(leftNode);
            Array.Copy(tmp, 0, b, index, tmp.Length);
            index += tmp.Length;

            tmp = BitConverter.GetBytes(rightNode);
            Array.Copy(tmp, 0, b, index, tmp.Length);
            index += tmp.Length;

            tmp = BitConverter.GetBytes(position);
            Array.Copy(tmp, 0, b, index, tmp.Length);
            index += tmp.Length;
        }

        public void LoadFrom(byte[] b, int startIndex)
        {
            int index = startIndex;

            key = new Key();
            key.LoadFrom(b, index);
            index += key.Size();

            radius = BitConverter.ToSingle(b, index);
            index += 4;

            disToParent = BitConverter.ToSingle(b, index);
            index += 4;

            lMax = BitConverter.ToSingle(b, index);
            index += 4;

            rMin = BitConverter.ToSingle(b, index);
            index += 4;

            leftNode = BitConverter.ToUInt64(b, index);
            index += 8;

            rightNode = BitConverter.ToUInt64(b, index);
            index += 8;

            position = BitConverter.ToInt32(b, index);
            index += 4;
        }

        public void SetKey(MPKey k)
        {
            key = k;
        }

        public MPKey GetKey()
        {
            return key;
        }

        public void SetRadius(float r)
        {
            radius = r;
        }

        public float GetRadius()
        {
            return radius;
        }

        public void SetDisToParent(float d)
        {
            disToParent = d;
        }

        public float GetDisToParent()
        {
            return disToParent;
        }

        public void SetLeftMax(float lMax)
        {
            this.lMax = lMax;
        }

        public float GetLeftMax()
        {
            return lMax;
        }

        public void SetRightMin(float rMin)
        {
            this.rMin = rMin;
        }

        public float GetRightMin()
        {
            return rMin;
        }

        public void SetLeftPage(ulong page)
        {
            leftNode = page;
        }

        public ulong GetLeftPage()
        {
            return leftNode;
        }

        public void SetRightPage(ulong page)
        {
            rightNode = page;
        }

        public ulong GetRightPage()
        {
            return rightNode;
        }

        public void SetNode(MPNode<Key> node)
        {
            this.node = node;
        }

        public MPNode<Key> GetNode()
        {
            return node;
        }

        public void SetPos(int pos)
        {
            position = pos;
        }

        public int GetPos()
        {
            return position;
        }

        public MPEntry<Key> Clone()
        {
            MPEntry<Key> entry = new MPEntry<Key>();
            entry.SetKey(key == null ? null : key.Clone());
            entry.SetRadius(radius);
            entry.SetDisToParent(disToParent);
            entry.SetLeftMax(lMax);
            entry.SetRightMin(rMin);
            entry.SetLeftPage(leftNode);
            entry.SetRightPage(rightNode);
            entry.SetNode(node);
            entry.SetPos(position);
            return entry;
        }
    }
}
